using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace CGF
{
    public class Banner : MonoBehaviour
    {
        [System.Serializable]
        public class Page
        {
            public RectTransform page;
            public RectTransform tagOff, tagOn;
        }
        public enum State
        {
            Stay, Draging, DragResume, AutoSlide
        }
        public CButton viewport;
        public Page[] pages;
        public int currIndex { get; private set; }
        public State currState { get; private set; }

        public float switchInterval = 5;
        public float animDuration = 0.5f;
        public RectTransform rectTransform { get { return transform as RectTransform; } }
        private float width, switchTimer;
        private float tweenT, tweenB, tweenC, tweenD;
        //拖动
        private Canvas canvas;
        private Camera uiCamera;
        private float beginTouchX, preTouchX;
        //点击事件
        private Dictionary<int, Action> pageClickActions = new Dictionary<int, Action>();

        void Awake()
        {
            CanvasScaler canvasScaler = rectTransform.GetComponentInParent<CanvasScaler>();
            canvas = canvasScaler.GetComponent<Canvas>();
            if (canvas && canvas.renderMode != RenderMode.ScreenSpaceOverlay)
            {
                uiCamera = canvas.worldCamera;
            }

            viewport.rectTransform.anchorMin = new Vector2(0, 0);
            viewport.rectTransform.anchorMax = new Vector2(1, 1);
            viewport.rectTransform.offsetMin = new Vector2(0, 0);
            viewport.rectTransform.offsetMax = new Vector2(0, 0);

            switchTimer = Time.time + switchInterval;
            RefreshPoints();

            viewport.triggerInterval = 0f;
            viewport.transition = CButton.Transition.None;
            viewport.SetPress(StartDrag);
            viewport.SetClick(OnViewportClick);

            width = this.rectTransform.sizeDelta.x;
            for (int i = 0; i < pages.Length; i++)
            {
                pages[i].page.anchoredPosition = new Vector2(i == 0 ? 0 : width, 0);
            }
        }

        public void Init(float switchInterval = 10, float animDuration = 0.5f)
        {
            this.switchInterval = switchInterval;
            this.animDuration = animDuration;
        }

        /// <summary>
        /// 设置页面的点击事件（不能在Page上自行绑定Button,否则会影响拖动翻页功能）
        /// </summary>
        public void SetPageClickEvent(int pageIndex, Action onPageClick)
        {
            pageClickActions[pageIndex] = onPageClick;
        }

        private async void OnViewportClick()
        {
            await CTask.Wait(0.01f);//等待鼠标弹起，结束拖拽
            float touchUpX = ScreenToUGUIPoint(Input.mousePosition).x;
            if (Mathf.Abs(touchUpX - beginTouchX) < 20)
            {
                if (pageClickActions.ContainsKey(currIndex))
                {
                    pageClickActions[currIndex]?.Invoke();
                }
            }
        }

        private void StartDrag()
        {
            if (currState == State.Stay)
            {
                beginTouchX = ScreenToUGUIPoint(Input.mousePosition).x;
                preTouchX = beginTouchX;
                currState = State.Draging;
            }
        }

        public void Update()
        {
            if (pages == null || pages[0] == null || pages.Length < 2)
            {
                return;
            }
            if (!pages[0].page || !pages[0].tagOff || !pages[0].tagOn)
            {
                return;
            }
            RectTransform currPage = null;
            RectTransform anotherPage = null;
            switch (currState)
            {
                case State.Stay:
                    if (switchTimer < Time.time)
                    {
                        currIndex++;
                        if (currIndex > pages.Length - 1)
                        {
                            currIndex = 0;
                        }
                        RefreshPoints();
                        tweenT = 0;
                        tweenB = 0;
                        tweenC = -width;
                        tweenD = animDuration;
                        currState = State.AutoSlide;
                    }
                    break;
                case State.Draging:
                    switchTimer = Time.time + switchInterval;
                    float touchX = ScreenToUGUIPoint(Input.mousePosition).x;
                    float delta = touchX - preTouchX;
                    preTouchX = touchX;
                    currPage = pages[currIndex].page;
                    currPage.anchoredPosition += new Vector2(delta, 0);
                    if (currPage.anchoredPosition.x < 0)
                    {
                        if (currIndex < pages.Length - 1)
                        {
                            anotherPage = pages[currIndex + 1].page;
                            anotherPage.anchoredPosition = currPage.anchoredPosition + new Vector2(width, 0);
                        }
                    }
                    else
                    {
                        if (currIndex > 0)
                        {
                            anotherPage = pages[currIndex - 1].page;
                            anotherPage.anchoredPosition = currPage.anchoredPosition - new Vector2(width, 0);
                        }
                    }
                    if (Input.GetMouseButtonUp(0))
                    {
                        if (beginTouchX - touchX > width * 0.1f)
                        {
                            if (currIndex < pages.Length - 1)
                            {
                                currIndex++;
                                RefreshPoints();
                            }
                        }
                        else if (touchX - beginTouchX > width * 0.1f)
                        {
                            if (currIndex > 0)
                            {
                                currIndex--;
                                RefreshPoints();
                            }
                        }
                        currState = State.DragResume;
                    }
                    break;
                case State.DragResume:
                    switchTimer = Time.time + switchInterval;
                    currPage = pages[currIndex].page;
                    Vector2 pos = currPage.anchoredPosition;
                    pos.x += (0 - pos.x) * 0.3f;
                    currPage.anchoredPosition = pos;
                    if (currPage.anchoredPosition.x < 0)
                    {
                        if (currIndex < pages.Length - 1)
                        {
                            anotherPage = pages[currIndex + 1].page;
                            anotherPage.anchoredPosition = currPage.anchoredPosition + new Vector2(width, 0);
                        }
                    }
                    else
                    {
                        if (currIndex > 0)
                        {
                            anotherPage = pages[currIndex - 1].page;
                            anotherPage.anchoredPosition = currPage.anchoredPosition - new Vector2(width, 0);
                        }
                    }
                    if (Mathf.Abs(0 - pos.x) < 1f)
                    {
                        currPage.anchoredPosition = Vector2.zero;
                        currState = State.Stay;
                    }
                    break;
                case State.AutoSlide:
                    tweenT += Time.deltaTime;
                    bool finish = false;
                    if (tweenT >= tweenD)
                    {
                        finish = true;
                        tweenT = tweenD;
                    }
                    if (currIndex == 0)
                    {
                        currPage = pages[pages.Length - 1].page;
                        anotherPage = pages[currIndex].page;
                    }
                    else
                    {
                        currPage = pages[currIndex - 1].page;
                        anotherPage = pages[currIndex].page;
                    }
                    pos = currPage.anchoredPosition;
                    pos.x = EaseCubicInOut(tweenT, tweenB, tweenC, tweenD);
                    currPage.anchoredPosition = pos;
                    anotherPage.anchoredPosition = pos + new Vector2(width, 0);
                    if (finish)
                    {
                        switchTimer = Time.time + switchInterval;
                        currState = State.Stay;
                    }
                    break;
            }
        }

        private void RefreshPoints()
        {
            for (int i = 0; i < pages.Length; i++)
            {
                pages[i].tagOff.anchoredPosition = i != currIndex ? Vector2.zero : new Vector2(9999, 9999);
                pages[i].tagOn.anchoredPosition = i == currIndex ? Vector2.zero : new Vector2(9999, 9999);
            }
        }

        //屏幕转换到UGUI坐标
        private Vector2 ScreenToUGUIPoint(Vector2 screenPos)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, screenPos, uiCamera, out Vector2 uiPos);
            return uiPos;
        }

        private float EaseCubicInOut(double t, double b, double c, double d)
        {
            if ((t /= d / 2) < 1)
            {
                return (float)(c / 2 * t * t * t + b);
            }
            return (float)(c / 2 * ((t -= 2) * t * t + 2) + b);
        }

#if UNITY_EDITOR
        [UnityEditor.MenuItem("CGFramework/创建 Banner")]
        [UnityEditor.MenuItem("GameObject/CGFramework/创建 Banner", priority = -2200)]
        static void Create()
        {
            GameObject go = new GameObject(nameof(Banner));
            go.layer = LayerMask.NameToLayer("UI");
            go.transform.SetParent(UnityEditor.Selection.activeGameObject.transform, false);
            RectTransform goTrans = go.AddComponent<RectTransform>();
            goTrans.sizeDelta = new Vector2(900, 500);

            Banner banner = go.AddComponent<Banner>();

            GameObject viewport = new GameObject("Viewport");
            viewport.layer = LayerMask.NameToLayer("UI");
            viewport.transform.SetParent(go.transform, false);
            viewport.AddComponent<Image>();
            RectTransform viewportTrans = viewport.transform as RectTransform;
            viewportTrans.anchorMin = new Vector2(0, 0);
            viewportTrans.anchorMax = new Vector2(1, 1);
            viewportTrans.offsetMin = new Vector2(0, 0);
            viewportTrans.offsetMax = new Vector2(0, 0);
            CButton viewportBtn = viewport.AddComponent<CButton>();
            viewportBtn.triggerInterval = 0;
            viewportBtn.globalSound = false;
            viewportBtn.transition = CButton.Transition.None;
            Mask viewportMask = viewport.AddComponent<Mask>();
            viewportMask.showMaskGraphic = false;
            banner.viewport = viewportBtn;

            GameObject points = new GameObject("Tags");
            points.layer = LayerMask.NameToLayer("UI");
            points.transform.SetParent(go.transform, false);
            RectTransform pointsTrans = points.AddComponent<RectTransform>();
            pointsTrans.anchorMin = new Vector2(0, 0);
            pointsTrans.anchorMax = new Vector2(1, 0);
            pointsTrans.offsetMin = new Vector2(0, 38);
            pointsTrans.offsetMax = new Vector2(0, 38);
            HorizontalLayoutGroup horizontalLayoutGroup = points.AddComponent<HorizontalLayoutGroup>();
            horizontalLayoutGroup.spacing = 30;
            horizontalLayoutGroup.childAlignment = TextAnchor.MiddleCenter;
            horizontalLayoutGroup.childControlWidth = false;
            horizontalLayoutGroup.childControlHeight = false;
            horizontalLayoutGroup.childScaleWidth = false;
            horizontalLayoutGroup.childScaleHeight = false;
            horizontalLayoutGroup.childForceExpandWidth = false;
            horizontalLayoutGroup.childForceExpandHeight = false;

            banner.pages = new Page[2];
            for (int i = 0; i < banner.pages.Length; i++)
            {
                GameObject photo = new GameObject("Page" + i);
                photo.layer = LayerMask.NameToLayer("UI");
                photo.transform.SetParent(viewport.transform, false);
                photo.AddComponent<RawImage>();
                banner.pages[i] = new Page();
                banner.pages[i].page = photo.transform as RectTransform;
                banner.pages[i].page.sizeDelta = goTrans.sizeDelta;

                GameObject point = new GameObject("Tag" + i);
                point.layer = LayerMask.NameToLayer("UI");
                point.transform.SetParent(points.transform, false);
                RectTransform pointTrans = point.AddComponent<RectTransform>();
                pointTrans.sizeDelta = Vector2.zero;

                GameObject off = new GameObject("Off");
                off.layer = LayerMask.NameToLayer("UI");
                off.transform.SetParent(pointTrans, false);
                Image offImg = off.AddComponent<Image>();
                offImg.rectTransform.sizeDelta = new Vector2(20, 20);
                banner.pages[i].tagOff = offImg.rectTransform;

                GameObject on = new GameObject("On");
                on.layer = LayerMask.NameToLayer("UI");
                on.transform.SetParent(pointTrans, false);
                Image onImg = on.AddComponent<Image>();
                onImg.rectTransform.sizeDelta = new Vector2(20, 20);
                banner.pages[i].tagOn = onImg.rectTransform;
            }

            UnityEditor.EditorUtility.SetDirty(go);
        }
#endif
    }
}